/*
 * @Author: song
 * @Description: GpuInstance 只展示样例 通过GpuInstance 绘制3D UI _imgIndex为背景底框 _headUV 是头像的UV
 * @Date: 2024年04月15日 星期一 16:04:55
 * @Modify:
 */

using System.Collections.Generic;
using SCore.Util;
using UnityEngine;
using UnityEngine.Rendering;

namespace SCore.Function.GupInstance
{
    public class GpuInstance : Singleton<GpuInstance>, IUpdatable
    {
        public struct GupInstanceDraw
        {
            public Transform _tran;
            public int _index;
            public Sprite _head;

            public GupInstanceDraw(int imgIndex, Transform transform, Sprite head)
            {
                _index = imgIndex;
                _tran = transform;
                _head = head;
            }

            public GupInstanceDraw SetUp(int imgIndex, Sprite head)
            {
                _index = imgIndex;
                _head = head;
                return this;
            }
        }

        private int _spriteTex; //精灵
        private int _imgIndex; //背景框
        private int _headUV; //头像


        private Dictionary<Transform, GupInstanceDraw> _draws;
        private MaterialPropertyBlock _materialPropertyBlock;
        private Material _material;
        private float[] _imgIndexs;
        private Vector4[] _headUVs;

        private Mesh _mesh;

        private Mesh Mesh
        {
            get
            {
                if (_mesh == null)
                {
                    _mesh = CreateQuad();
                }

                return _mesh;
            }
        }

        private static Mesh CreateQuad()
        {
            Mesh quadMesh = new Mesh();
            Vector3[] vertices = new Vector3[]
            {
                new Vector3(-4f, 0.27f, 0f),
                new Vector3(4f, 0.27f, 0f),
                new Vector3(-4f, -0.27f, 0f),
                new Vector3(4f, -0.27f, 0f)
            };
            // 定义 Quad 的三角形索引
            int[] triangles = new int[] { 0, 1, 2, 1, 3, 2 };

            // 定义 Quad 的 UV 坐标
            Vector2[] uv = new Vector2[]
            {
                new Vector2(0, 1),
                new Vector2(1, 1),
                new Vector2(0, 0),
                new Vector2(1, 0)
            };

            // 设置 Mesh 的顶点、三角形索引和 UV 坐标
            quadMesh.vertices = vertices;
            quadMesh.triangles = triangles;
            quadMesh.uv = uv;

            // 重新计算法线和切线
            quadMesh.RecalculateNormals();
            return quadMesh;
        }

        public override void Init()
        {
            _spriteTex = Shader.PropertyToID("_Main4Tex");
            _imgIndex = Shader.PropertyToID("imgIndex");
            _headUV = Shader.PropertyToID("headUV");

            _materialPropertyBlock = new MaterialPropertyBlock();
            _draws = new Dictionary<Transform, GupInstanceDraw>();
            _imgIndexs = new float[200];
            _headUVs = new Vector4[200];

            UnityUpdate.Instance.Register(this);
        }

        public override void Clear()
        {
            _draws.Clear();
            _materialPropertyBlock = null;
            UnityUpdate.Instance.UnRegister(this);
        }

        public void SUpdate(float dt)
        {
            if (_draws.Count > 0)
            {
                Matrix4x4[] matrix4 = new Matrix4x4[_draws.Count];
                int offest = 0;
                foreach (var draw in _draws)
                {
                    matrix4[offest] = draw.Value._tran.localToWorldMatrix;
                    _imgIndexs[offest] = draw.Value._index;
                    var sprite = draw.Value._head;
                    _headUVs[offest] = sprite.GetUV();
                    if (offest == 0)
                    {
                        _material.SetTexture(_spriteTex, sprite.texture);
                    }

                    offest++;
                }

                _materialPropertyBlock.SetFloatArray(_imgIndex, _imgIndexs);
                _materialPropertyBlock.SetVectorArray(_headUV, _headUVs);
                Graphics.DrawMeshInstanced(Mesh, 0, _material, matrix4, _draws.Count, _materialPropertyBlock,
                    ShadowCastingMode.Off, false, 0, null, LightProbeUsage.Off, null);
            }
        }

        //添加GpuDrawItem
        public void AddDraw(Transform transform, int index, Sprite sprite)
        {
            if (!_draws.ContainsKey(transform))
                _draws.Add(transform, new GupInstanceDraw(index, transform, sprite));
            else
                _draws[transform] = _draws[transform].SetUp(index, sprite);
        }

        public void RemoveDraw(Transform transform)
        {
            if (_draws.ContainsKey(transform))
                _draws.Remove(transform);
        }
    }
}